package com.fouram.auth.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.crypto.digest.BCrypt;
import com.fouram.core.constants.CacheConstants;
import com.fouram.core.constants.SecurityConstants;
import com.fouram.core.domain.LoginUser;
import com.fouram.core.exception.BizException;
import com.fouram.core.service.TokenService;
import com.fouram.core.utils.IpUtils;
import com.fouram.core.utils.StringUtils;
import com.fouram.redis.util.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.Duration;

/**
 * 登录校验方法
 * 
 * @author ruoyi
 */
@Component
public class SysLoginService {

    private int maxRetryCount = CacheConstants.PASSWORD_MAX_RETRY_COUNT;
    private Long lockTime = CacheConstants.PASSWORD_LOCK_TIME;

    @Autowired
    private TokenService tokenService;

    /**
     * 登录
     */
    public String login(String username, String password) {
        // 用户名或密码为空 错误
        if (StringUtils.isAnyBlank(username, password)) {
            throw new BizException("用户/密码必须填写");
        }
        LoginUser redisUser = null;
        if (SecurityConstants.ADMIN_USER.equals(username)
                && SecurityConstants.ADMIN_PWD.equals(password)) {
            redisUser = new LoginUser();
            redisUser.setUserId(SecurityConstants.ADMIN_ID);
            redisUser.setUsername(username);
        } else {
            // IP黑名单校验
            String blackStr = Convert.toStr(RedisUtils.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST));
            if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) {
                throw new BizException("很遗憾，访问IP已被列入系统黑名单");
            }
            // 需要先把用户信息按照RedisUser格式放到redis缓存
            redisUser = RedisUtils.getCacheObject(CacheConstants.SYS_USER_KEY + username);
            if (redisUser == null) {
                throw new BizException("用户不存在");
            }
            validatePassword(username, password, redisUser.getEncPassword());
        }
        return tokenService.login(redisUser);
    }

    public void validatePassword(String username, String password, String encPassword) {
        String pwdErrCountKey = CacheConstants.PWD_ERR_COUNT_KEY + username;
        Integer retryCount = RedisUtils.getCacheObject(pwdErrCountKey);
        if (retryCount == null) {
            retryCount = 0;
        }
        if (retryCount >= Integer.valueOf(maxRetryCount).intValue()) {
            String errMsg = String.format("密码输入错误%s次，帐户锁定%s分钟", maxRetryCount, lockTime);
            throw new BizException(errMsg);
        }
        if (!BCrypt.checkpw(password, encPassword)) {
            retryCount = retryCount + 1;
            RedisUtils.setCacheObject(pwdErrCountKey, retryCount, Duration.ofMinutes(lockTime));
            throw new BizException("密码错误");
        } else {
            if (RedisUtils.hasKey(pwdErrCountKey)) {
                RedisUtils.deleteObject(pwdErrCountKey);
            }
        }
    }
}